home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / web / knit / twist.ch < prev   
Text File  |  1992-09-23  |  43KB  |  1,139 lines

  1. % This is twist.ch
  2. This is a changefile for WEAVE which produces TWIST, a version of WEAVE
  3. which allows multiple changefiles (see TUGBoat Vol.7, No. 1, pg. 20-21).
  4. @x We modify the text
  5. @* Introduction.
  6. This program converts a \.{WEB} file to a \TeX\ file. It was written
  7. by D. E. Knuth in October, 1981; a somewhat similar {\mc SAIL} program had
  8. been developed in March, 1979, although the earlier program used a top-down
  9. parsing method that is quite different from the present scheme.
  10. @y
  11. \def\title{TWIST}
  12. \def\contentspagenumber{1} % should be odd
  13. \def\topofcontents{\null\vfill
  14.   \titlefalse % include headline on the contents page
  15.   \def\rheader{\mainfont Appendix E\hfil \contentspagenumber}
  16.   \centerline{\titlefont The {\ttitlefont TWIST} processor}
  17.   \vskip 15pt
  18.   \centerline{(Version 2.7)}
  19.   \vfill}
  20. \pageno=\contentspagenumber \advance\pageno by 1
  21. @* Introduction.
  22. This program converts a \.{WEB} file to a \TeX\ file.  Several
  23. changes have been made by GMD, to allow \.{WEAVE} to handle more
  24. than one |change_file|. It is basically the original \.{WEAVE} written by
  25. D.E. Knuth, but we'll name this \.{WEAVE}--Version \.{TWIST} to distinguish it
  26. from the original one. The program was created by writing a |change_file|
  27. modifying |weave.web|. To keep that |change_file| as small as possible we
  28. didn't change the name "\.{WEAVE}" througout the documentation.
  29. \bigskip
  30. If you find a bug in the program you should send a message to:
  31.  
  32. {\obeylines\parskip=0pt
  33.       W.Appelt, K.Horn
  34.       GMD Gesellschaft f\"ur Mathematik und Datenverarbeitung
  35.       Schlo\ss\ Birlinghoven
  36.       Postfach 1240
  37.       D-5205 Sankt Augustin
  38.  
  39.       West-Germany
  40.  
  41. }
  42. \bigskip
  43. The original version was written
  44. by D. E. Knuth in October, 1981; a somewhat similar {\mc SAIL} program had
  45. been developed in March, 1979, although the earlier program used a top-down
  46. parsing method that is quite different from the present scheme.
  47. @z
  48.  
  49. @x (1) we modify the banner line
  50. The ``banner line'' defined here should be changed whenever \.{WEAVE}
  51. is modified.
  52.  
  53. @d banner=='This is WEAVE, Version 2.8'
  54. @y
  55. The ``banner line'' defined here should be changed whenever \.{TWIST}
  56. is modified.
  57. @d banner=='This is TWIST based on WEAVE, Version 2.8 knitted by GMD'
  58. @d term_in==input
  59. @d term_out==output
  60. @z
  61.  
  62. @x (2) Now we allow three change-files
  63. @ The program begins with a fairly normal header, made up of pieces that
  64. @^system dependencies@>
  65. will mostly be filled in later. The \.{WEB} input comes from files |web_file|
  66. and |change_file|, and the \TeX\ output goes to file |tex_file|.
  67. @y
  68. @ Changes have been made to allow more than one |change_file|.
  69. To mark changed modules we won't use the asteriks as \.{WEAVE} does, but
  70. we'll indicate the number or numbers of the corresponding
  71. |change_files| influencing the actual module.
  72. In this \.{TWIST}--version three |change_files| are used. The necessary new
  73. definitions are inserted quite below this explanation, so don't be
  74. astonished to find a macro-definition in this module.
  75. Changing the number of |change-files| only causes updates in this
  76. module.
  77.  
  78. The |change_files| have descending priorities. That means, if two
  79. |change_files| want to modify the same line in a |web_file| , there will be a
  80. warning and  the |change_file| with the lower priority will be advanced
  81. to the next section without influencing the input.
  82. If a |change_file| wants to modify lines within the |web_file| which
  83. are currently already changed by another |change_file| then changes
  84. are ignored.
  85. A warning will be generated.
  86.  
  87. First you should examine this little example of \.{TWIST} with three
  88. |change_files|:
  89.  
  90. \bigskip
  91. Input files:
  92. $$\vbox{{\tt
  93. \halign{&
  94. \quad#\hfill\quad&\quad#\hfill\quad&\quad#\hfill\quad&\quad#\hfill\quad\cr
  95. |web_file|  &   |ch_file_1|  &  |ch_file_2|  &  |ch_file_3|     \cr
  96. line1       &   @@x          &  @@x          &  @@x             \cr
  97. line2       &   line1        &  line5        &  line1           \cr
  98. line3       &   @@y          &  @@y          &  line2           \cr
  99. line4       &   line1from1   &  line5from2   &  @@y             \cr
  100. line5       &   line2from1   &  @@z          &  line1from3      \cr
  101. line6       &   line3from1   &  @@x          &  @@z             \cr
  102. line7       &   @@z          &  line10       &  @@x             \cr
  103. line8       &   *EOF*        &  @@y          &  line4           \cr
  104. line9       &                &  line10from2  &  line5           \cr
  105. line10      &                &  line11from2  &  line6           \cr
  106. line11      &                &  @@z          &  @@y             \cr
  107. line12      &                &  *EOF*        &  line4from3      \cr
  108. *EOF*       &                &               &  line5from3      \cr
  109.         &                &               &  @@z             \cr
  110.         &                &               &  *EOF*           \cr
  111. }}
  112. }
  113. $$
  114.  
  115. The result will be that the program will input the following lines:
  116.  
  117. {\tt\obeylines
  118. ***WARNING...     (ch\_file\_3 will be advanced)
  119. line1from1
  120. line2from1
  121. line3from1
  122. line2
  123. line3
  124. ***WARNING...     (ch\_file\_2 will be advanced)
  125. line4from3
  126. line5from3
  127. line7
  128. line8
  129. line9
  130. line10from2
  131. line11from2
  132. line11
  133. line12
  134. *EOF*
  135. }
  136.  
  137. Now we want to explain the macros defined in this module. They serve to
  138. avoid arrays of files since some PASCAL-compilers can't
  139. handle arrays of files. Behind this we find the main-program's skeleton.
  140.  
  141. The program begins with a fairly normal header, made up of pieces that
  142. @^system dependencies@>
  143. will mostly be filled in later. The \.{WEB} input comes
  144. from the file |web_file| and from the files |change_files|, and the
  145. \TeX\ output goes to file |tex_file|.
  146. @z
  147.  
  148. @x we have to split the change-file to allow system dependent changes
  149. @d end_of_WEAVE = 9999 {go here to wrap it up}
  150. @y
  151. @d end_of_WEAVE = 9999 {go here to wrap it up}
  152.  
  153. @d ch_max==3  {indicates the maximum number of |change_files| with descending
  154. priority, if this number is modified the following three definitions and
  155. the program statement must be updated as well, further don't forget to
  156. initialize the array prime[1..ch\_max] properly}
  157.  
  158. @d input_ch(#) == case # of
  159.           1: ch_not_eof:=input_ln(ch_file_1);
  160.           2: ch_not_eof:=input_ln(ch_file_2);
  161.           3: ch_not_eof:=input_ln(ch_file_3);end
  162.  
  163. @d reset_ch(#) == case # of
  164.           1: reset(ch_file_1);
  165.           2: reset(ch_file_2);
  166.           3: reset(ch_file_3);end
  167.  
  168. @d declaration_ch_files ==@/
  169.             @! ch_file_1:text_file;
  170.             @! ch_file_2:text_file;
  171.             @! ch_file_3:text_file
  172.  
  173. @d decl_prime == @! prime:array[1..ch_max] of integer
  174. {augmenting the number of |change_files| don't forget to add the
  175. corresponding prime number in the initialisation above}
  176.  
  177. @z
  178.  
  179. @x (2) program header,term_in and term_out (this shouldn't make worry)
  180. program WEAVE(@!web_file,@!change_file,@!tex_file);
  181. @y
  182. program TWIST(@!term_in,@!term_out,@!web_file,@!ch_file_1,@!ch_file_2,
  183.            @!ch_file_3,@!tex_file);
  184. @z
  185.  
  186. @x We define the prime numbers
  187. procedure initialize;
  188.   var @<Local variables for initialization@>@/
  189.   begin @<Set initial values@>@/
  190.   end;
  191. @y
  192. procedure initialize;
  193.   var @<Local variables for initialization@>@/
  194.   begin @<Set initial values@>
  195. prime[1]:=2;
  196. prime[2]:=3;
  197. prime[3]:=5;   {augmenting the number of |change__ files| add a prime-number}
  198. end;
  199. @z
  200.  
  201. @x Default in case statement is otherwise. (7)
  202. @d othercases == others: {default for cases not listed explicitly}
  203. @y
  204. @d othercases == otherwise {default for cases not listed explicitly}
  205. @z
  206. @x term_out (output) must not be redefined. (20)
  207. @!term_out:text_file; {the terminal as an output file}
  208. @y
  209. @z
  210.  
  211. @x term_out (output) must not be opened. (21)
  212. rewrite(term_out,'TTY:'); {send |term_out| output to the terminal}
  213. @y
  214. @z
  215.  
  216. @x break is replaced by writeln (22)
  217. @d update_terminal == break(term_out) {empty the terminal output buffer}
  218. @y
  219. @d update_terminal == write_ln(term_out) {empty the terminal output buffer}
  220. @z
  221.  
  222. @x (23) we declare the maximum number (ch_max) of change-files
  223. @ The main input comes from |web_file|; this input may be overridden
  224. by changes in |change_file|. (If |change_file| is empty, there are no changes.)
  225.  
  226. @<Globals...@>=
  227. @!web_file:text_file; {primary input}
  228. @!change_file:text_file; {updates}
  229. @y
  230. @ The main input comes from |web_file|; this input may be overridden
  231. by changes in the |change_files|. The |change_files| have descending
  232. priority. Only one change may be done to the same text in the |web_file|.
  233. (If all |change_files| are empty, there are no changes.)
  234. Whenever the number of |change_files| is increased the correspondent
  235. file-declarations have to be modified. Since we have written a macro
  236. for this in module~2 of \.{TWIST}, no more changes are necessary here.
  237.  
  238. @<Globals...@>=
  239. @!web_file:text_file; {primary input}
  240. declaration_ch_files; {look for the macro definitions at the beginning}
  241. decl_prime; {look for the macro definition at the beginning}
  242. @z
  243.  
  244. @x (24) we have to reset all change-files explicitely
  245. @ The following code opens the input files.  Since these files were listed
  246. in the program header, we assume that the \PASCAL\ runtime system has
  247. already checked that suitable file names have been given; therefore no
  248. additional error checking needs to be done. We will see below that
  249. \.{WEAVE} reads through the entire input twice.
  250. @^system dependencies@>
  251.  
  252. @p procedure open_input; {prepare to read |web_file| and |change_file|}
  253. begin reset(web_file); reset(change_file);
  254. end;
  255. @y
  256. @ The following code opens the input files.  Since these files were listed
  257. in the program header, we assume that the \PASCAL\ runtime system has
  258. already checked that suitable file names have been given; therefore no
  259. additional error checking needs to be done. We will see below that
  260. \.{WEAVE} reads through the entire input twice.
  261. @^system dependencies@>
  262. The macro |reset_ch(i)| resets the |i-th change_file|.
  263. This is done by a macro,
  264. so changing the number of |change_files| only makes necessary a modification
  265. in the macro written in module~2 of the \.{TWIST}--program.
  266.  
  267. @p procedure open_input; {prepare to read |web_file| and |change_file|}
  268. var i:integer; {loop variable for processing the |change_files|}
  269. begin reset(web_file); for i:=1 to ch_max do reset_ch(i);end;
  270. @z
  271.  
  272. @x (32) We want to specify the current change-file
  273. @ The error locations can be indicated by using the global variables
  274. |loc|, |line|, and |changing|, which tell respectively the first
  275. unlooked-at position in |buffer|, the current line number, and whether or not
  276. the current line is from |change_file| or |web_file|.
  277. This routine should be modified on systems whose standard text editor
  278. has special line-numbering conventions.
  279. @^system dependencies@>
  280.  
  281. @<Print error location based on input buffer@>=
  282. begin if changing then print('. (change file ')@+else print('. (');
  283. print_ln('l.', line:1, ')');
  284. if loc>=limit then l:=limit else l:=loc;
  285. for k:=1 to l do
  286.   if buffer[k-1]=tab_mark then print(' ')
  287.   else print(xchr[buffer[k-1]]); {print the characters already read}
  288. new_line;
  289. for k:=1 to l do print(' '); {space out the next line}
  290. for k:=l+1 to limit do print(xchr[buffer[k-1]]); {print the part not yet read}
  291. if buffer[limit]="|" then print(xchr["|"]);
  292.   {end of \PASCAL\ text in module names}
  293. print(' '); {this space separates the message from future asterisks}
  294. end
  295. @y
  296. @ The error locations can be indicated by using the global variables
  297. |loc|, |line|, and |changing|, which tell respectively the first
  298. unlooked-at position in |buffer|, the current line number, and whether or not
  299. the current line is from a |change_file| (and if yes, from which one)
  300. or from |web_file|. The variable |ch_act| gives the index of
  301. the current |change_file|.
  302. This routine should be modified on systems whose standard text editor
  303. has special line-numbering conventions.
  304. @^system dependencies@>
  305.  
  306. @<Print error location based on input buffer@>=
  307. begin if changing then print('. (change file ',ch_act:1,' ')@+
  308. else print('. (');
  309. print_ln('l.', line:1, ')');
  310. if loc>=limit then l:=limit else l:=loc;
  311. for k:=1 to l do
  312.   if buffer[k-1]=tab_mark then print(' ')
  313.   else print(xchr[buffer[k-1]]); {print the characters already read}
  314. new_line;
  315. for k:=1 to l do print(' '); {space out the next line}
  316. for k:=l+1 to limit do print(xchr[buffer[k-1]]); {print the part not yet read}
  317. if buffer[limit]="|" then print(xchr["|"]);
  318.   {end of \PASCAL\ text in module names}
  319. print(' '); {this space separates the message from future asterisks}
  320. end
  321. @z
  322.  
  323. @x (45) we specify the actual change file
  324. @ We keep track of the current module number in
  325. |module_count|, which is the total number of modules that have started.
  326. Modules which have been altered by a change file entry
  327. have their |changed_module| flag turned on during the first phase.
  328.  
  329. @<Globals...@>=
  330. @!module_count:0..max_modules; {the current module number}
  331. @!changed_module: packed array [0..max_modules] of boolean; {is it changed?}
  332. @!change_exists: boolean; {has any module changed?}
  333. @y
  334. @ We keep track of the current module number in
  335. |module_count|, which is the total number of modules that have started.
  336. Modules which have been altered by a |change_file|--entry
  337. have their |changed_module| flag turned on during the first phase.
  338. Since we have to work with more than one |change_file| we cannot
  339. use a boolean flag. We have decided to associate a prime number
  340. with each |change_file| and to multiply the flag's value with this
  341. prime number if the module is changed by that |change_file|. The
  342. initial value for the |changed_module|--flag is one.
  343. A value different from one, indicates that a change has been made.
  344.  
  345. @<Globals...@>=
  346. @!module_count:0..max_modules; {the current module number}
  347. @!changed_module: packed array [0..max_modules] of integer;
  348. {keeps a product of primes or 1}
  349. @!change_exists: integer; {unequal 1 if a module has changed}
  350. @z
  351.  
  352. @x (70) we define a type |ch_type| to characterise the local parameter
  353. @* Lexical scanning.
  354. Let us now consider the subroutines that read the \.{WEB} source file
  355. and break it into meaningful units. There are four such procedures:
  356. One simply skips to the next `\.{@@\ }' or `\.{@@*}' that begins a
  357. module; another passes over the \TeX\ text at the beginning of a
  358. module; the third passes over the \TeX\ text in a \PASCAL\ comment;
  359. and the last, which is the most interesting, gets the next token of
  360. a \PASCAL\ text.
  361. @y
  362. @* Lexical scanning.
  363. Let us now consider the subroutines that read the \.{WEB} source file
  364. and break it into meaningful units. There are four such procedures:
  365. One simply skips to the next `\.{@@\ }' or `\.{@@*}' that begins a
  366. module; another passes over the \TeX\ text at the beginning of a
  367. module; the third passes over the \TeX\ text in a \PASCAL\ comment;
  368. and the last, which is the most interesting, gets the next token of
  369. a \PASCAL\ text.
  370.  
  371. In the \.{TWIST}--version of \.{WEAVE} there is more than one |change_file|.
  372. So there are some modifications, which will be explained when they are made.
  373. Altering the number of |change_files| only causes modifications in module~2
  374. of \.{TWIST} since we decided to use macros whereever
  375. the number of |change_files| is important.
  376.  
  377. We need a type |ch_type| to describe the local parameters. This will be done
  378. here.
  379.  
  380. @<Types...@>=
  381. @!ch_type=1..ch_max;
  382. @z
  383.  
  384. @x (73) we expand |change_buffer|, |change_limit| and |ch_line| one dimension
  385. @ When |changing| is |false|, the next line of |change_file| is kept in
  386. |change_buffer[0..change_limit]|, for purposes of comparison with the next
  387. line of |web_file|. After the change file has been completely input, we
  388. set |change_limit:=0|, so that no further matches will be made.
  389.  
  390. @<Globals...@>=
  391. @!change_buffer:array[0..buf_size] of ASCII_code;
  392. @!change_limit:0..buf_size; {the last position occupied in |change_buffer|}
  393. @y
  394. @ Different to the original version we are able to handle more than
  395. one |change_file|. So the variable |change_buffer| and
  396. |change_limit| need one more dimension to indicate the current |change_file|.
  397. The index of the current |change_file| will be kept in the variable |ch_act|.
  398. It is set by the function |lines_dont_match|. The variable |ch_not_eof|
  399. takes the value of the |input_ln| function when the input comes from a
  400. |change_file|. To understand why we need this you should look up
  401. the macro definition of |input_ch(#)| in module~2 of \.{TWIST}.
  402. The current line numbers of the |web_file| and all the |change_files|
  403. have to be managed. In the original version this could be done with the
  404. macro |change_changing| defined in the previous module. \.{TWIST} has to handle
  405. more than two files, so we use the array |ch_line| to keep the current line
  406. numbers of all |change_files|. The variable |line| will be updated from
  407. this array each time it is used.
  408. When |changing| is |false|, the next lines of the
  409. |change_files| are kept in their |change_buffers|.
  410. The length of the |change_buffers| are kept in |change_limit[i]|.
  411. After a |change_file| has been completely input, we
  412. set its |change_limit:=0|, so that no further matches will be made.
  413.  
  414. @<Globals...@>=
  415. @!change_buffer:array[1..ch_max,0..buf_size] of ASCII_code;
  416. @!change_limit:array[1..ch_max] of 0..buf_size;
  417.               {the last position occupied in |change_buffer|}
  418. @!ch_act:1..ch_max; {specifies the current |change_file|}
  419. @!i:1..ch_max;{index used for loops}
  420. @!ch_not_eof:boolean;{corresponds to the boolean |input_ln|}
  421. @!ch_line:array[1..ch_max] of integer; {line refering to all |change_file|s}
  422. @z
  423.  
  424. @x (74) we define an additional function ch_dont_match
  425. @ Here's a simple function that checks if the two buffers are different.
  426.  
  427. @p function lines_dont_match:boolean;
  428. label exit;
  429. var k:0..buf_size; {index into the buffers}
  430. begin lines_dont_match:=true;
  431. if change_limit<>limit then return;
  432. if limit>0 then
  433.   for k:=0 to limit-1 do if change_buffer[k]<>buffer[k] then return;
  434. lines_dont_match:=false;
  435. exit: end;
  436. @y
  437. @ Differing from the original version the index of the current |change_buffer|
  438. has to be specified as function parameter.
  439. The function |lines_dont_match| checks if |change_buffer[i]| is equal to
  440. the buffer filled by |web_file|. If so, the index of the |change_file|
  441. is copied to the variable |ch_act|. The function |ch_dont_match| checks
  442. if two |change_buffers| are equal.
  443.  
  444. @p function lines_dont_match(i:ch_type):boolean;
  445. label exit;
  446. var k:0..buf_size; {index into the buffers}
  447. begin lines_dont_match:=true;
  448. if change_limit[i]<>limit then return;
  449. if limit>0 then
  450.   for k:=0 to limit-1 do if change_buffer[i,k]<>buffer[k] then return;
  451. ch_act:=i;
  452. lines_dont_match:=false;
  453. exit: end;
  454. @t\hskip 2in@>
  455.  
  456. function ch_dont_match(i,j:ch_type):boolean;
  457. label exit;
  458. var k:0..buf_size; {index into the buffers}
  459. begin ch_dont_match:=true;
  460. if ((change_limit[i]=0) or (change_limit[j]=0)) then return;
  461. if change_limit[i]<>change_limit[j] then return;
  462. if change_limit[i]>0 then
  463.    for k:=0 to change_limit[i]-1
  464.        do if change_buffer[i,k]<>change_buffer[j,k] then return;
  465. ch_dont_match:=false;
  466. exit: end;
  467. @z
  468.  
  469. @x (75) now we have to manage more than one change-file
  470. @ Procedure |prime_the_change_buffer| sets |change_buffer| in preparation
  471. for the next matching operation. Since blank lines in the change file are
  472. not used for matching, we have |(change_limit=0)and not changing| if and
  473. only if the change file is exhausted. This procedure is called only
  474. when |changing| is true; hence error messages will be reported correctly.
  475.  
  476. @p procedure prime_the_change_buffer;
  477. label continue, done, exit;
  478. var k:0..buf_size; {index into the buffers}
  479. begin change_limit:=0; {this value will be used if the change file ends}
  480. @<Skip over comment lines in the change file; |return| if end of file@>;
  481. @<Skip to the next nonblank line; |return| if end of file@>;
  482. @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>;
  483. exit: end;
  484. @y
  485. @ Procedure |prime_the_change_buffer| sets the indexed
  486. |change_buffer| in preparation
  487. for the next matching operation. Since blank lines in the change file are
  488. not used for matching, we have |(change_limit=0)and not changing| if and
  489. only if the change file is exhausted. This procedure is called only
  490. when |changing| is true; hence error messages will be reported correctly.
  491.  
  492. The procedure |pre_prime_the_change_buffer| is necessary if there are two
  493. equal |change_buffers|. The one with the lower priority or the one which
  494. is currently not compared with the buffer filled by |web_file| will be advanced
  495. to the next matching position behind the @@x-line. First we have to skip over
  496. the @@x...@@y...@@z passage before we call the original
  497. |prime_the_change_buffer|.
  498.  
  499. The procedure |compare_change_files| checks if the |change_buffers| of all
  500. |change_files| are equal. If so, those one with the lower priority will be
  501. advanced.
  502.  
  503. @p procedure prime_the_change_buffer(i:ch_type);
  504. label continue, done, exit;
  505. var k:0..buf_size; {index into the buffers}
  506. begin change_limit[i]:=0; {this value will be used if the change file ends}
  507. @<Skip over comment lines in the change file; |return| if end of file@>;
  508. @<Skip to the next nonblank line; |return| if end of file@>;
  509. @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>;
  510. exit: end;
  511. @t\hskip 2in@>
  512.  
  513. procedure pre_prime_the_change_buffer(i:ch_type);
  514. label continue, done, exit;
  515. begin change_limit[i]:=0; {this value will be used if the change file ends}
  516. loop@+ begin line:=ch_line[i];incr(line);ch_line[i]:=line;
  517.    input_ch(i);
  518.    if not ch_not_eof then
  519.       begin err_print ('! Change file ',i:1,' ended without @@z');
  520.       return end;
  521.    if limit < 2 then goto continue;
  522.    if ((buffer[0]="@@") and ((buffer[1]="z") or (buffer[1]="Z")))
  523.       then goto done;
  524. continue:end;
  525. done:
  526. prime_the_change_buffer(i);
  527. exit: end;
  528. @t\hskip 2in@>
  529.  
  530. procedure compare_change_files;
  531. label restart;
  532. var i,j:0..ch_max;
  533. begin
  534. restart:
  535. for i:=1 to ch_max-1 do
  536.    for j:=i+1 to ch_max do
  537.    if not ch_dont_match(i,j) then
  538.       begin
  539.       print_nl(' WARNING: change_file ',i:1,' line ',ch_line[i]:4);
  540.       print_nl('      and change_file ',j:1,' line ',ch_line[j]:4,
  541.           ' refer to the same text !!!!');
  542.       print_nl(' Change_file ',j:1,' will be advanced.');new_line;
  543.       pre_prime_the_change_buffer(j);
  544.       mark_harmless; goto restart
  545.       end;
  546. end;
  547. @z
  548.  
  549. @x (76) we have to use an index for change-file
  550. @ While looking for a line that begins with \.{@@x} in the change file,
  551. we allow lines that begin with \.{@@}, as long as they don't begin with
  552. \.{@@y} or \.{@@z} (which would probably indicate that the change file is
  553. fouled up).
  554.  
  555. @<Skip over comment lines in the change file...@>=
  556. loop@+  begin incr(line);
  557.   if not input_ln(change_file) then return;
  558.   if limit<2 then goto continue;
  559.   if buffer[0]<>"@@" then goto continue;
  560.   if (buffer[1]>="X")and(buffer[1]<="Z") then
  561.     buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
  562.   if buffer[1]="x" then goto done;
  563.   if (buffer[1]="y")or(buffer[1]="z") then
  564.     begin loc:=2; err_print('! Where is the matching @@x?');
  565. @.Where is the match...@>
  566.     end;
  567. continue: end;
  568. done:
  569. @y
  570. @ While looking for a line that begins with \.{@@x} in the change file,
  571. indexed by |i|,
  572. we allow lines that begin with \.{@@}, as long as they don't begin with
  573. \.{@@y} or \.{@@z} (which would probably indicate that the change file is
  574. fouled up).
  575.  
  576. @<Skip over comment lines in the change file...@>=
  577. loop@+  begin line:=ch_line[i];incr(line);ch_line[i]:=line;
  578.   input_ch(i);
  579.   if not ch_not_eof then return;
  580.   if limit<2 then goto continue;
  581.   if buffer[0]<>"@@" then goto continue;
  582.   if (buffer[1]>="X")and(buffer[1]<="Z") then
  583.     buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
  584.   if buffer[1]="x" then goto done;
  585.   if (buffer[1]="y")or(buffer[1]="z") then
  586.     begin loc:=2;
  587.       err_print('! Where is the matching @@x in change-file ',i:1,' ?');
  588. @.Where is the match...@>
  589.     end;
  590. continue: end;
  591. done:
  592. @z
  593.  
  594. @x (77) we have to use an index using change-file
  595. @ Here we are looking at lines following the \.{@@x}.
  596.  
  597. @<Skip to the next nonblank line...@>=
  598. repeat incr(line);
  599.   if not input_ln(change_file) then
  600.     begin err_print('! Change file ended after @@x');
  601. @.Change file ended...@>
  602.     return;
  603.     end;
  604. until limit>0;
  605. @y
  606. @ Here we are looking at lines following the \.{@@x}.
  607.  
  608. @<Skip to the next nonblank line...@>=
  609. repeat line:=ch_line[i];incr(line);ch_line[i]:=line;
  610.   input_ch(i);
  611.   if not ch_not_eof then
  612.     begin err_print('! Change file ',i:1,' ended after @@x');
  613. @.Change file ended...@>
  614.     return;
  615.     end;
  616. until limit>0;
  617. @z
  618.  
  619. @x (78) we have to specify the change-file by an index
  620. @ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>=
  621. begin change_limit:=limit;
  622. if limit>0 then for k:=0 to limit-1 do change_buffer[k]:=buffer[k];
  623. end
  624. @y
  625. @ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>=
  626. begin change_limit[i]:=limit;
  627. if limit>0 then for k:=0 to limit-1 do change_buffer[i,k]:=buffer[k];
  628. end
  629. @z
  630.  
  631. @x (79) we have to specify and work with the actual change-file
  632. @ The following procedure is used to see if the next change entry should
  633. go into effect; it is called only when |changing| is false.
  634. The idea is to test whether or not the current
  635. contents of |buffer| matches the current contents of |change_buffer|.
  636. If not, there's nothing more to do; but if so, a change is called for:
  637. All of the text down to the \.{@@y} is supposed to match. An error
  638. message is issued if any discrepancy is found. Then the procedure
  639. prepares to read the next line from |change_file|.
  640.  
  641. @p procedure check_change; {switches to |change_file| if the buffers match}
  642. label exit;
  643. var n:integer; {the number of discrepancies found}
  644. @!k:0..buf_size; {index into the buffers}
  645. begin if lines_dont_match then return;
  646. n:=0;
  647. loop@+  begin change_changing; {now it's |true|}
  648.   incr(line);
  649.   if not input_ln(change_file) then
  650.     begin err_print('! Change file ended before @@y');
  651. @.Change file ended...@>
  652.     change_limit:=0;  change_changing; {|false| again}
  653.     return;
  654.     end;
  655.   @<If the current line starts with \.{@@y},
  656.     report any discrepancies and |return|@>;
  657.   @<Move |buffer| and |limit|...@>;
  658.   change_changing; {now it's |false|}
  659.   incr(line);
  660.   if not input_ln(web_file) then
  661.     begin err_print('! WEB file ended during a change');
  662. @.WEB file ended...@>
  663.     input_has_ended:=true; return;
  664.     end;
  665.   if lines_dont_match then incr(n);
  666.   end;
  667. exit: end;
  668. @y
  669. @ The following procedure is used to see if the next change entry should
  670. go into effect; it is called only when |changing| is false.
  671. The idea is to test whether or not the current contents of |buffer|
  672. matches the current contents of one of the |change_buffers|.
  673. If not, there's nothing more to do; but if so, a change is called for:
  674. All of the text down to the \.{@@y} is supposed to match. An error
  675. message is issued if any discrepancy is found. Then the procedure
  676. prepares to read the next line from the current |change_file|.
  677.  
  678. Since we use several |change_file|s we first have to examine all
  679. |change_buffer|s. The index of the matching |change_file| is written to the
  680. variable |ch_act| by the function |lines_dont_match|.
  681. Each time one line of the current |change_file| is read into its
  682. |change_buffer| this one is compared with all other |change_buffers|.
  683. In case of equality the latter |change_file| will be advanced by the
  684. function |pre_prime_the_change_buffer|.
  685.  
  686.  
  687. @p procedure check_change; {switches to |change_file| if the buffers match}
  688. label exit,done,continue;
  689. var n:integer; {index, the number of discrepancies found}
  690.     i:integer; {loop variable for processing the |change_files|}
  691.     temp:integer; {for temporary storage of the contents of |ch_act|}
  692. @!k:0..buf_size; {index into the buffers}
  693. begin
  694. for i:= 1 to ch_max do
  695.    if not lines_dont_match(i) then goto done;
  696.    return;{no change-file matches}
  697. done:{one change-file matches, the index has been written to ch-act}
  698.   n:=0;
  699. loop@+  begin change_changing; {now it's |true|}
  700.   line:=ch_line[ch_act];incr(line);ch_line[ch_act]:=line;
  701.   input_ch(ch_act);
  702.   if not ch_not_eof then
  703.     begin err_print('! Change file ',ch_act:1,' ended before @@y');
  704. @.Change file ended...@>
  705.     change_limit[ch_act]:=0;  change_changing; {|false| again}
  706.     return;
  707.     end;
  708.   @<If the current line starts with \.{@@y},
  709.     report any discrepancies and |return|@>;
  710.   @<Move |buffer| and |limit|...@>;
  711. {the actual change-buffer has to be compared with the other change-buffers,
  712. the index of the actual |change_file| is stored to the variable temp}
  713.     temp:=ch_act;
  714.     for i:=1 to ch_max do
  715.     begin
  716.     if i=ch_act then goto continue;
  717.     if not ch_dont_match(i,ch_act) then
  718.        begin
  719.        print_nl(' WARNING: change_file ',i:1,' line ',ch_line[i]:4);
  720.        print_nl('      and change_file ',ch_act:1,' line ',
  721.              ch_line[ch_act]:4,' refer to the same text !!!!');
  722.        print_nl(' Change_file ',i:1,' will be advanced.');new_line;
  723.        pre_prime_the_change_buffer(i);
  724.        end;
  725.     continue: end;
  726.   ch_act:=temp;i:=ch_act; {the actual index has to be reloaded}
  727.   change_changing; {now it's |false|}
  728.   incr(line);
  729.   if not input_ln(web_file) then
  730.     begin err_print('! WEB file ended during a change');
  731. @.WEB file ended...@>
  732.     input_has_ended:=true; return;
  733.     end;
  734.   if lines_dont_match(ch_act)  then incr(n);
  735.   end;
  736. exit: end;
  737. @z
  738.  
  739. @x (80) we specify the actual change-file in the error message
  740. @ @<If the current line starts with \.{@@y}...@>=
  741. if limit>1 then if buffer[0]="@@" then
  742.   begin if (buffer[1]>="X")and(buffer[1]<="Z") then
  743.     buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
  744.   if (buffer[1]="x")or(buffer[1]="z") then
  745.     begin loc:=2; err_print('! Where is the matching @@y?');
  746. @.Where is the match...@>
  747.     end
  748.   else if buffer[1]="y" then
  749.     begin if n>0 then
  750.       begin loc:=2; err_print('! Hmm... ',n:1,
  751.     ' of the preceding lines failed to match');
  752. @.Hmm... n of the preceding...@>
  753.       end;
  754.     return;
  755.     end;
  756.   end
  757. @y
  758. @ @<If the current line starts with \.{@@y}...@>=
  759. if limit>1 then if buffer[0]="@@" then
  760.   begin if (buffer[1]>="X")and(buffer[1]<="Z") then
  761.     buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
  762.   if (buffer[1]="x")or(buffer[1]="z") then
  763.     begin loc:=2;
  764.     err_print('! Where is the matching @@y in change_file ',ch_act:1,' ?');
  765. @.Where is the match...@>
  766.     end
  767.   else if buffer[1]="y" then
  768.     begin if n>0 then
  769.       begin loc:=2; err_print('! Hmm... ',n:1,
  770.     ' of the preceding lines failed to match in change_file ',ch_act:1);
  771. @.Hmm... n of the preceding...@>
  772.       end;
  773.     return;
  774.     end;
  775.   end
  776. @z
  777.  
  778. @x (81) to initialize we have to look at all change buffers
  779. @ The |reset_input| procedure, which gets \.{WEAVE} ready to read the
  780. user's \.{WEB} input, is used at the beginning of phases one and two.
  781.  
  782. @p procedure reset_input;
  783. begin open_input; line:=0; other_line:=0;@/
  784. changing:=true; prime_the_change_buffer; change_changing;@/
  785. limit:=0; loc:=1; buffer[0]:=" "; input_has_ended:=false;
  786. end;
  787. @y
  788. @ The |reset_input| procedure, which gets \.{WEAVE} ready to read the
  789. user's \.{WEB} input, is used at the beginning of phases one and two.
  790.  
  791. @p procedure reset_input;
  792. var i : integer; {local loop variable}
  793. begin open_input; line:=0; other_line:=0;@/
  794. for i:=1 to ch_max do ch_line[i]:=0;@/
  795. changing:=true;
  796. for i:=1 to ch_max do  prime_the_change_buffer(i);@/
  797. compare_change_files;change_changing;@/
  798. limit:=0; loc:=1; buffer[0]:=" "; input_has_ended:=false;
  799. end;
  800. @z
  801.  
  802. @x (82) we need a loop variable i and to store the module number
  803. @ The |get_line| procedure is called when |loc>limit|; it puts the next
  804. line of merged input into the buffer and updates the other variables
  805. appropriately. A space is placed at the right end of the line.
  806.  
  807. @p procedure get_line; {inputs the next line}
  808. label restart;
  809. begin restart: if changing then changed_module[module_count]:=true
  810. else  @<Read from |web_file| and maybe turn on |changing|@>;
  811. if changing then
  812.   begin @<Read from |change_file| and maybe turn off |changing|@>;
  813.   if not changing then
  814.     begin changed_module[module_count]:=true; goto restart;
  815.     end;
  816.   end;
  817. loc:=0; buffer[limit]:=" ";
  818. end;
  819. @y
  820. @ The |get_line| procedure is called when |loc>limit|; it puts the next
  821. line of merged input into the buffer and updates the other variables
  822. appropriately. A space is placed at the right end of the line.
  823.  
  824. In \.{TWIST} we add the procedure |set_index|. The idea is, that we don't
  825. only want to mark a module as changed, as in the \.{WEAVE}--version with a
  826. single |change_file|, but we want to enumerate all numbers of those
  827. |change_files| influencing the module.
  828.  
  829. The i-th |change_file| is represented by the i-th prime. Using
  830. primes allows us to verify easily whether the actual |change_file|
  831. is already marked by the value of |changed_module[m]|. This
  832. is neccessary since each time a line is read from a |change_file|
  833. \.{TWIST}  wants to mark its number in |changed_module[m]|.
  834.  
  835.  
  836. @p procedure set_index(m,i:integer);
  837. { m specifies the module, i specifies the |change_file| to be taken as index}
  838. begin
  839. if changed_module[m] mod prime[i] <> 0
  840.    then changed_module[m] := changed_module[m] * prime[i];
  841. end;
  842. @#
  843. procedure get_line; {inputs the next line}
  844. label restart;var i:integer;{ loop variable for processing the change files}
  845. ch_flag:boolean; {flag whether to use |check_change| or not}
  846. begin restart: if changing then set_index(module_count,ch_act)
  847. else  @<Read from |web_file| and maybe turn on |changing|@>;
  848. if changing then
  849.   begin @<Read from |change_file| and maybe turn off |changing|@>;
  850.   if not changing then
  851.     begin set_index(module_count,ch_act); goto restart;
  852.     end;
  853.   end;
  854. loc:=0; buffer[limit]:=" ";
  855. end;
  856. @z
  857.  
  858. @x (83) we have to specify the actual change-file
  859. @ @<Read from |web_file|...@>=
  860. begin incr(line);
  861. if not input_ln(web_file) then input_has_ended:=true
  862. else if limit=change_limit then
  863.   if buffer[0]=change_buffer[0] then
  864.     if change_limit>0 then check_change;
  865. end
  866. @y
  867. @ @<Read from |web_file|...@>=
  868. begin incr(line);
  869. if not input_ln(web_file) then input_has_ended:=true
  870. else begin ch_flag:=false;
  871.      for i:=1 to ch_max do begin
  872.      if limit=change_limit[i] then
  873.   if buffer[0]=change_buffer[i,0] then
  874.     if change_limit[i]>0 then ch_flag:=true;  end;
  875.      if ch_flag then check_change;end;
  876. end
  877. @z
  878.  
  879. @x (84) we have to specify the change-file
  880. @ @<Read from |change_file|...@>=
  881. begin incr(line);
  882. if not input_ln(change_file) then
  883.   begin err_print('! Change file ended without @@z');
  884. @.Change file ended...@>
  885.   buffer[0]:="@@"; buffer[1]:="z"; limit:=2;
  886.   end;
  887. if limit>1 then {check if the change has ended}
  888.   if buffer[0]="@@" then
  889.     begin if (buffer[1]>="X")and(buffer[1]<="Z") then
  890.       buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
  891.     if (buffer[1]="x")or(buffer[1]="y") then
  892.       begin loc:=2; err_print('! Where is the matching @@z?');
  893. @.Where is the match...@>
  894.       end
  895.     else if buffer[1]="z" then
  896.       begin prime_the_change_buffer; change_changing;
  897.       end;
  898.     end;
  899. end
  900. @y
  901. @ @<Read from |change_file|...@>=
  902. begin line:=ch_line[ch_act];incr(line);ch_line[ch_act]:=line;
  903. input_ch(ch_act);
  904. if not ch_not_eof then
  905.   begin err_print('! Change file ',ch_act:1,' ended without @@z');
  906. @.Change file ended...@>
  907.   buffer[0]:="@@"; buffer[1]:="z"; limit:=2;
  908.   end;
  909. if limit>1 then {check if the change has ended}
  910.   if buffer[0]="@@" then
  911.     begin if (buffer[1]>="X")and(buffer[1]<="Z") then
  912.       buffer[1]:=buffer[1]+"z"-"Z"; {lowercasify}
  913.     if (buffer[1]="x")or(buffer[1]="y") then
  914.       begin loc:=2; err_print('! Where is the matching @@z in change_file ',
  915.                    ch_act:1,' ?');
  916. @.Where is the match...@>
  917.       end
  918.     else if buffer[1]="z" then
  919.       begin prime_the_change_buffer(ch_act);
  920.         compare_change_files; change_changing;
  921.       end;
  922.     end;
  923. end
  924. @z
  925.  
  926. @x (85) we have to specify the actual change-file
  927. @ At the end of the program, we will tell the user if the change file
  928. had a line that didn't match any relevant line in |web_file|.
  929.  
  930. @<Check that all changes have been read@>=
  931. if change_limit<>0 then {|changing| is false}
  932.   begin for loc:=0 to change_limit do buffer[loc]:=change_buffer[loc];
  933.   limit:=change_limit; changing:=true; line:=other_line; loc:=change_limit;
  934.   err_print('! Change file entry did not match');
  935. @y
  936. @ At the end of the program, we will tell the user if one of the
  937. |change_file|s had a line that didn't match any relevant line in |web_file|.
  938.  
  939. @<Check that all changes have been read@>=
  940. for i:=1 to ch_max do begin
  941. if change_limit[i]<>0 then {|changing| is false}
  942.   begin for loc:=0 to change_limit[i] do buffer[loc]:=change_buffer[i,loc];
  943.   limit:=change_limit[i]; changing:=true; line:=ch_line[i];
  944.   loc:=change_limit[i];
  945.   ch_act:=i;
  946.   err_print('! Change_file ',i:1,' entry did not match');
  947. @.Change file entry did not match@>
  948.   end
  949. @z
  950.  
  951. @x (109) we have to specify the change-file number
  952. @ The overall processing strategy in phase one has the following
  953. straightforward outline.
  954.  
  955. @<Phase I: Read all the user's text and store the cross references@>=
  956. phase_one:=true; phase_three:=false;
  957. reset_input;
  958. module_count:=0; skip_limbo; change_exists:=false;
  959. while not input_has_ended do
  960.   @<Store cross reference data for the current module@>;
  961. changed_module[module_count]:=change_exists;
  962.   {the index changes if anything does}
  963. phase_one:=false; {prepare for second phase}
  964. @<Print error messages about unused or undefined module names@>;
  965. @y
  966. @ The overall processing strategy in phase one has the following
  967. straightforward outline.
  968.  
  969. @<Phase I: Read all the user's text and store the cross references@>=
  970. phase_one:=true; phase_three:=false;
  971. reset_input;
  972. module_count:=0; skip_limbo; change_exists:=1;
  973. while not input_has_ended do
  974.   @<Store cross reference data for the current module@>;
  975. changed_module[module_count]:=change_exists;
  976.   {the index changes if anything does}
  977. phase_one:=false; {prepare for second phase}
  978. @<Print error messages about unused or undefined module names@>;
  979. @z
  980.  
  981. @x (110) we have to ask for zero instead of false
  982. @ @<Store cross reference data...@>=
  983. begin incr(module_count);
  984. if module_count=max_modules then overflow('section number');
  985. changed_module[module_count]:=false; {it will become |true| if any line changes}
  986. if buffer[loc-1]="*" then
  987.   begin print('*',module_count:1);
  988.   update_terminal; {print a progress report}
  989.   end;
  990. @<Store cross references in the \TeX\ part of a module@>;
  991. @<Store cross references in the \(definition part of a module@>;
  992. @<Store cross references in the \PASCAL\ part of a module@>;
  993. if changed_module[module_count] then change_exists:=true;
  994. end
  995. @y
  996. @ @<Store cross reference data...@>=
  997. begin incr(module_count);
  998. if module_count=max_modules then overflow('section number');
  999. changed_module[module_count]:=1;{it will become |<>1| if any line changes}
  1000. if buffer[loc-1]="*" then
  1001.   begin print('*',module_count:1);
  1002.   update_terminal; {print a progress report}
  1003.   end;
  1004. @<Store cross references in the \TeX\ part of a module@>;
  1005. @<Store cross references in the \(definition part of a module@>;
  1006. @<Store cross references in the \PASCAL\ part of a module@>;
  1007. if changed_module[module_count] <> 1 then
  1008. change_exists:=changed_module[module_count];
  1009. end
  1010. @z
  1011.  
  1012. @x
  1013. `\.{\\input webmac}'.
  1014.  
  1015. @<Set init...@>=
  1016. out_ptr:=1; out_line:=1; out_buf[1]:="c"; write(tex_file,'\input webma');
  1017. @y
  1018. `\.{\\input patchmac}'.
  1019.  
  1020. @<Set init...@>=
  1021. out_ptr:=1; out_line:=1; out_buf[1]:="c"; write(tex_file,'\input patchma');
  1022. @z
  1023.  
  1024. @x (130)we indicate the change-file's number instead of an asteriks
  1025. @ The number to be converted by |out_mod| is known to be less than
  1026. |def_flag|, so it cannot have more than five decimal digits.  If
  1027. the module is changed, we output `\.{\\*}' just after the number.
  1028.  
  1029. @p procedure out_mod(@!m:integer); {output a module number}
  1030. var k:0..5; {index into |dig|}
  1031. @!a:integer; {accumulator}
  1032. begin k:=0; a:=m;
  1033. repeat dig[k]:=a mod 10; a:=a div 10; incr(k);
  1034. until a=0;
  1035. repeat decr(k); out(dig[k]+"0");
  1036. until k=0;
  1037. if changed_module[m] then out2("\")("*");
  1038. @.\\*@>
  1039. end;
  1040. @y
  1041. @ The number to be converted by |out_mod| is known to be less than
  1042. |def_flag|, so it cannot have more than five decimal digits.  If
  1043. the module is changed, we output the numbers of the corresponding
  1044. |change_files| as indices just after the number.
  1045. Since we coded the numbers of the influencing |change_files| as
  1046. the product of the corresponding primes, we have to use the procedure
  1047. |out_index| to decode the corresponding numbers of the |change_files|.
  1048.  
  1049. @p procedure out_index(m:integer); {output the |change--file| number}
  1050. var i:integer;
  1051. begin
  1052. i:=1;
  1053. while m mod prime[i] <> 0 do incr(i);
  1054. out(i+"0");incr(i);
  1055. while i <= ch_max do begin
  1056.    if m mod prime[i] = 0 then begin out(",");out(i+"0") end;
  1057.    incr(i) end;
  1058. end;
  1059. @#
  1060. procedure out_mod(@!m:integer); {output a module number}
  1061. var k:0..5; {index into |dig|}
  1062. @!a:integer; {accumulator}
  1063. begin k:=0; a:=m;
  1064. repeat dig[k]:=a mod 10; a:=a div 10; incr(k);
  1065. until a=0;
  1066. repeat decr(k); out(dig[k]+"0");
  1067. until k=0;
  1068. if changed_module[m] <> 1 then begin out3("$")("^")("{");
  1069.  out_index(changed_module[m]);out2("}")("$");end
  1070. @.\\*@>
  1071. end;
  1072. @z
  1073.  
  1074. @x (239) change_exist now is an integer-variable
  1075. We are nearly finished! \.{WEAVE}'s only remaining task is to write out the
  1076. index, after sorting the identifiers and index entries.
  1077.  
  1078. @<Phase III: Output the cross-reference index@>=
  1079. phase_three:=true; print_nl('Writing the index...');
  1080. if change_exists then
  1081.   begin finish_line; @<Tell about changed modules@>;
  1082.   end;
  1083. finish_line; out4("\")("i")("n")("x"); finish_line;
  1084. @.\\inx@>
  1085. @<Do the first pass of sorting@>;
  1086. @<Sort and output the index@>;
  1087. out4("\")("f")("i")("n"); finish_line;
  1088. @.\\fin@>
  1089. @<Output all the module names@>;
  1090. out4("\")("c")("o")("n"); finish_line;
  1091. @.\\con@>
  1092. print('Done.');
  1093. @y
  1094. We are nearly finished! \.{WEAVE}'s only remaining task is to write out the
  1095. index, after sorting the identifiers and index entries.
  1096.  
  1097. @<Phase III: Output the cross-reference index@>=
  1098. phase_three:=true; print_nl('Writing the index...');
  1099. if change_exists <> 1 then
  1100.   begin finish_line; @<Tell about changed modules@>;
  1101.   end;
  1102. finish_line; out4("\")("i")("n")("x"); finish_line;
  1103. @.\\inx@>
  1104. @<Do the first pass of sorting@>;
  1105. @<Sort and output the index@>;
  1106. out4("\")("f")("i")("n"); finish_line;
  1107. @.\\fin@>
  1108. @<Output all the module names@>;
  1109. out4("\")("c")("o")("n"); finish_line;
  1110. @.\\con@>
  1111. print('Done.');
  1112. @z
  1113.  
  1114. @x (241) we indicate the change-file's number instead of an asteriks
  1115. @ @<Tell about changed modules@>=
  1116. begin {remember that the index is already marked as changed}
  1117. k_module:=1;
  1118. while not changed_module[k_module] do incr(k_module);
  1119. out4("\")("c")("h")(" ");
  1120. out_mod(k_module);
  1121. repeat repeat incr(k_module)@+ until changed_module[k_module];
  1122.   out2(",")(" "); out_mod(k_module);
  1123. until k_module=module_count;
  1124. out(".");
  1125. end
  1126. @y
  1127. @ @<Tell about changed modules@>=
  1128. begin {remember that the index is already marked as changed}
  1129. k_module:=1;
  1130. while changed_module[k_module] = 1 do incr(k_module);
  1131. out4("\")("c")("h")(" ");
  1132. out_mod(k_module);
  1133. repeat repeat incr(k_module)@+ until changed_module[k_module] <> 1;
  1134.   out2(",")(" "); out_mod(k_module);
  1135. until k_module=module_count;
  1136. out(".");
  1137. end
  1138. @z
  1139.